package com.chris.design.pattern.samples.singleton;

/**
 * 双重检查加锁 单例, 既实现线程安全，又能够使性能不受很大的影响.
 * 所谓“双重检查加锁”机制，指的是：并不是每次进入getInstance方法都需要同步，
 * 而是先不同步，进入方法后，先检查实例是否存在，如果不存在才进行下面的同步块，这是第一重检查，
 * 进入同步块过后，再次检查实例是否存在，如果不存在，就在同步的情况下创建一个实例，这是第二重检查。
 * 这样一来，就只需要同步一次了，从而减少了多次在同步情况下进行判断所浪费的时间。
 *
 * “双重检查加锁”机制的实现会使用关键字volatile, 需要jdk1.5+
 */
public class DoubleCheckLockSingleton {

    /** volatile, 指令重排的优化 */
    private static volatile DoubleCheckLockSingleton instance = null;

    private DoubleCheckLockSingleton() {
    }

    /**
     * volatile关键字可能会屏蔽掉虚拟机中一些必要的代码优化，所以运行效率并不是很高。
     * 目标：既能实现延迟加载，又能实现线程安全
     * @return DoubleCheckLockSingleton
     */
    public static DoubleCheckLockSingleton getInstance() {
        // 先检查实例是否存在，如果不存在才进入下面的同步块
        if (instance == null) {
            // 同步块，线程安全的创建实例
            synchronized (DoubleCheckLockSingleton.class) {
                // 再次检查实例是否存在，如果不存在才真正的创建实例
                if (instance == null) {
                    instance = new DoubleCheckLockSingleton();
                }
            }
        }
        return instance;
    }
}
